<?php if(!defined('BASEPATH')) exit('No direct access to this file allowed');
/******************************************************************************\
 *  Profiler
 *
 *  Change Log
 *  0.1     -   Initial version of Profiler
 *
 *  Standard Tags:
 *  @author     Ruben Tan
 *  @copyright  Copyright (c) 2008 Rendervault
 *
 *  Developer Tags:
 *  @package    system
 *  @subpackage core
\******************************************************************************/
class Profiler
{
    protected $_points = array();
    
    protected $_is_enabled = TRUE;
    
    protected $_decimals = 6;
    protected $_dec_point = '.';
    protected $_thousands_sep = '';

    /**--------------------------------------------------------------------------------------
     *  Profiler constructor
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     void
     */
    public function __construct( $IB )
    { }
    
    /**--------------------------------------------------------------------------------------
     *  Begins profiling the application
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     void
     */
    public function begin( )
    {
        if( !$this->get_enabled( ) ) return;
        
        // Clean up all profile points by default
        $this->_points = array( );
        
        $this->mark( 'begin' );
    }
    
    /**--------------------------------------------------------------------------------------
     *  Marks a profiling point in the system
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      string      profile point name
     *  @return     void
     */
    public function mark( $point_name )
    {
        // 'end' is a reserved word
        if( !$this->get_enabled( ) ) return;
    
        // Make sure the profiler has been started and is running
        if( !array_key_exists( 'begin', $this->_points ) || $point_name === 'begin' ) 
        {
            $this->_points['begin'] = microtime( TRUE );
        }
        //else
        {
            $this->_points[$point_name] = microtime( TRUE );
        }
    }
    
    /**--------------------------------------------------------------------------------------
     *  Marks the end point of the profiling routine
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     void
     */
    protected function end( )
    {
        if( !$this->get_enabled( ) ) return;
        
        $this->mark( 'end' );
    }
    
    /**--------------------------------------------------------------------------------------
     *  Get a profiling point in the system
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      string      profiling point's name. 'begin' to get the beginning
     *                          and 'end' to get the end point.
     *  @param      boolean     TRUE to format the results using number_format
     *  @return     boolean     the profile point's time if exists, FALSE if 
     *                          otherwise
     */
    public function get_point($point_name, $format_result = TRUE)
    {
        if(array_key_exists($point_name, $this->_points) && isset($this->_points[$point_name]))
        {
            return ( $format_result ) ? $this->_format( $this->_points[$point_name] ) : $this->_points[$point_name];
        }
        
        
        return FALSE;
    }
    
    /**--------------------------------------------------------------------------------------
     *  Calculate the elapsed time between two profile points
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      string      profile point's name
     *  @param      string      porfile point to compare to
     *  @return     double      the elapsed time
     */
    public function elapsed( $point_name = '', $previous_point = '' )
    {
        $result = 0.0;
        
        if( $point_name === 'begin' )
        {
            $result = 0.0;
        }
        elseif( array_key_exists( $point_name, $this->_points ) && 
                array_key_exists( $previous_point, $this->_points ))
        {
            $result = $this->_points[$point_name] - $this->_points[$previous_point];
        }
        elseif( count( $this->_points ) > 1 )
        {
            $result =  end($this->_points) - reset($this->_points);
        }
        
        return $this->_format($result);
    }
    
    /**--------------------------------------------------------------------------------------
     *  Returns an array containing all profile points (including begin and end)
     *  and their respective timestamps.
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     array       profile data (all profile points, begin and end) in
     *                          an associative array. the key 'name' denotes the 
     *                          profile point, 'elapsed' denotes the time passed
     *                          between this profile point and the previous one,
     *                          and 'time' denotes its respective timestamp
     */
    public function get_profile_data( )
    {
        $this->end();
        
        $data = array( );
        
        $previous_point = 'begin';
        
        foreach( $this->_points as $key => $time )
        {
            $data[] = array('name' => $key, 
                            'elapsed' => $this->elapsed( $key, $previous_point ), 
                            'time' => $this->get_point( $key ));
            
            $previous_point = $key;
        }
        
        return $data;
    }
    
    /**--------------------------------------------------------------------------------------
     *  Check if profiler is enabled or not
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      void
     *  @return     boolean     returns TRUE if profiler is enabled 
     */
    public function get_enabled( )
    {
        return $this->_is_enabled;
    }
    
    /**--------------------------------------------------------------------------------------
     *  Enables/disables the profiler
     *
     *  @author     Ruben Tan
     *
     *  @access     public
     *  @param      boolean     TRUE to enable, FALSE to disable
     *  @return     void
     */
    public function set_enabled( $enable )
    {
        $this->_is_enabled = $enabled;
    }
    
    /**--------------------------------------------------------------------------------------
     *  Formats the number
     *
     *  @author     Ruben Tan
     *
     *  @access     protected
     *  @param      float       the number to be formatted
     *  @return     float       the formatted number
     */
    protected function _format( $num )
    {
        return number_format( $num, $this->_decimals , $this->_dec_point, $this->_thousands_sep );
    }
}